home *** CD-ROM | disk | FTP | other *** search
-
- /* Generated by Interface Builder */
-
- #import "NXYController.h"
- #import "NXYView.h" /* only for initializeLegendBox */
- /* will get warning message from compiler if preceding line is commented out */
- #import <appkit/OpenPanel.h>
- #import <appkit/Matrix.h>
- #import <appkit/Cell.h>
- #import <math.h>
-
- #define ALLOCSIZE 2048 /* used in malloc in readData */
-
- @implementation NXYController
-
- - (NXCoord *)xdata { return x;}
- - (NXCoord **)ydata { return y;}
-
- - (int)nPoints { return npoints;}
- - (int)nCurves { return ncurves;}
-
- - (const char *)provideXtitle {return [xTitle stringValueAt:0];}
- - (const char *)provideYtitle {return [yTitle stringValueAt:0];}
- - (const char *)provideMaintitle {return [mainTitle stringValueAt:0];}
-
- - (const char *)provideCurveTitle:(int)aCurve
- {
- return [legendForm stringValueAt:aCurve];
- }
-
- - (const char *)provideLegendTitle
- {
- return [legendTitle stringValueAt:0];
- }
-
- - (BOOL) shouldDrawLegend
- {
- if ( [legendOnOff state] ) return YES;
- else return NO;
- }
- - (BOOL) shouldDrawLegendBox
- {
- if ( [legendBoxOnOff state] ) return YES;
- else return NO;
- }
-
- - (BOOL) shouldDrawGrid
- {
- if ( [gridOnOff state] ) return YES;
- else return NO;
- }
-
- - (BOOL) shouldDrawBox
- {
- if ( [borderBoxOnOff state] ) return YES;
- else return NO;
- }
-
- - (BOOL) shouldMoveLegend
- {
- if ( [legendMove state] ) return YES;
- else return NO;
- }
-
- - (BOOL) doZoom
- {
- if ( [zoomOnOff state] ) return YES;
- else return NO;
- }
-
- - (BOOL) xaxisLog
- {
- if ( [xLinLog state] ) return YES;
- else return NO;
- }
-
- - forceXaxisLinear
- {
- [xLinLog setState:0];
- [xLinLog display];
- return self;
- }
-
- - (BOOL) yaxisLog
- {
- if ( [yLinLog state] ) return YES;
- else return NO;
- }
-
- - forceYaxisLinear
- {
- [yLinLog setState:0];
- [yLinLog display];
- return self;
- }
-
- - (int)providelinestyle:(int)aCurve
- {
- int row;
- int cellstate;
-
- for (row=0; row<N_LINE_STYLES; row++) {
- cellstate = [ [lineMatrix cellAt:row :aCurve] state];
- if (cellstate == 1) return row;
- }
- return 0; /* for safety */
- }
-
- - (int)providesymbolstyle:(int)aCurve
- {
- int row;
- int cellstate;
-
- for (row=0; row<N_SYMBOL_STYLES; row++) {
- cellstate = [ [symbolMatrix cellAt:row :aCurve] state];
- if (cellstate == 1) return row;
- }
- return 0; /* for safety */
- }
-
- - (int)providesymbolsize{ return [symbolSize selectedCol];}
- - (int)providelinethickness{ return [lineThickness selectedCol];}
-
- - (float)provideXmin {return [xMin floatValueAt:0];}
- - (float)provideXmax {return [xMax floatValueAt:0];}
- - (float)provideXinc {return [xInc floatValueAt:0];}
- - (float)provideYmin {return [yMin floatValueAt:0];}
- - (float)provideYmax {return [yMax floatValueAt:0];}
- - (float)provideYinc {return [yInc floatValueAt:0];}
-
- - resetXmin:(float)aNum { [xMin setFloatValue:aNum at:0]; return self; }
- - resetXmax:(float)aNum { [xMax setFloatValue:aNum at:0]; return self; }
- - resetXinc:(float)aNum { [xInc setFloatValue:aNum at:0]; return self; }
- - resetYmin:(float)aNum { [yMin setFloatValue:aNum at:0]; return self; }
- - resetYmax:(float)aNum { [yMax setFloatValue:aNum at:0]; return self; }
- - resetYinc:(float)aNum { [yInc setFloatValue:aNum at:0]; return self; }
-
- - resetMinMax:sender
- {
- [xMin setFloatValue:datamin.x at:0];
- [xMax setFloatValue:datamax.x at:0];
- [xInc setFloatValue:(datamax.x - datamin.x)/5.0 at:0];
- [yMin setFloatValue:datamin.y at:0];
- [yMax setFloatValue:datamax.y at:0];
- [yInc setFloatValue:(datamax.y - datamin.y)/5.0 at:0];
- return self;
- }
-
- - drawPlotButton:(int)state
- {
- if (state==0) {
- [plotButton highlight:NO]; /* will display normal title */
- }
- if (state==1) {
- [plotButton highlight:YES]; /* will display alternate title */
- }
- return self;
- }
-
- - drawPlot:sender
- {
- if (!x) return self;
-
- [self drawPlotButton:1]; /* display "Plotting" */
- [canvas display];
- [self drawPlotButton:0]; /* display "Plot" */
- return self;
- }
-
- // Allocate enough memory and read the data points
- /*
- * WARNING: This code will go into an infinite loop if there is illegal
- * crud in the data file (such as a comma, for example). The culprit is
- * the "fscanf" below; we will put up with this for now, but we should
- * make this more robust.
- */
- - (int) readData:(FILE *)aDataStream
- {
- BOOL inword = NO;
- char c;
- int j, size = ALLOCSIZE;
- int oldncurves = ncurves; /* for linestyle matrix column deleting */
-
- /* set plot button title "Reading" */
- [plotButton setAltTitle:"Reading"];
- [plotButton highlight:YES];
- NXPing(); /* force plotButton redraw */
-
- /* First, free x and y here if there's already data in them */
- if (x) {
- free( (void *)x );
- for (j = 0; j < ncurves; j++) {
- free( (void *)(*(y+j)) );
- }
- free( (void *)y );
- }
-
- /* Figure out the number of curves in the file by reading characters */
- /* until a newline is encountered; the number of curves is one less */
- /* than the number of words found. */
- /* For now we assume the input file is an ascii file. */
- ncurves = -1;
- while (1) {
- c = getc(aDataStream);
- if (c == '\n') {
- break; /* breaks out of while loop */
- }
- if ((inword==NO) && !(c==' ' || c=='\t')) {
- ncurves++;
- inword = YES;
- }
- if ((inword==YES) && (c==' ' || c=='\t')) {
- inword = NO;
- }
- }
- if (ncurves == -1) { /* couldn't find "\n", give up */
- return 0;
- }
-
- /* Now read the data into memory */
- rewind(aDataStream);
-
- y = (NXCoord **)malloc( ncurves * sizeof(NXCoord *) );
- x = (NXCoord *)malloc( size * sizeof(NXCoord) );
- for (j = 0; j < ncurves; j++) {
- *(y+j) = (NXCoord *)malloc( size * sizeof(NXCoord) );
- }
- npoints = 0;
- while(1) {
- if( (fscanf(aDataStream, "%f", x+npoints)) == EOF ) {
- break; /* breaks out of the while loop */
- }
- for (j = 0; j < ncurves; j++) {
- fscanf(aDataStream, "%f", *(y+j)+npoints);
- }
- npoints++;
- if (npoints == size) { /* get more memory */
- size += ALLOCSIZE;
- x = (NXCoord *)realloc(x, size * sizeof(NXCoord));
- for (j = 0; j < ncurves; j++) {
- *(y+j) = (NXCoord *)realloc( *(y+j), size * sizeof(NXCoord) );
- }
- }
- }
- /* Adjust the lineMatrix, symbolMatrix, and legendForm */
- [self adjustPanels:oldncurves :ncurves];
-
- /* reset plot button */
- [plotButton setAltTitle:"Plotting"];
- [plotButton highlight:NO];
- return npoints;
- }
-
- /* Might want to make sure INLINE_MATH is defined when math.h is included */
-
- - checkLinLog
- {
- /* Check x and y axes -- do a heuristic test for log/lin.
- * The test employed comes from M. Merriam and xyplot.
- */
- double scale, linsum, logsum;
- register double tmp;
- int i, j;
-
- /* First test x axis. */
- if (datamax.x > 0.0 && datamin.x > 0.0 && datamax.x != datamin.x) {
- scale = fabs( (double)datamax.x - (double)datamin.x );
- linsum = 0.0;
- for (j=1; j<npoints; j++) {
- tmp = ( (double)x[j]-(double)x[j-1] )/(double)scale; /* avoid overflow */
- linsum += tmp*tmp;
- }
- scale = log10( (double)datamax.x/(double)datamin.x );
- /* what if datamax.x<datamin.x? */
- logsum = 0.0;
- for (i=1; i<npoints; i++) {
- tmp = log10( (double)x[i]/(double)x[i-1] ) / scale;
- logsum += tmp*tmp;
- }
- if (linsum < logsum) {
- [xLinLog setState:0]; /* linear axis */
- }
- else {
- [xLinLog setState:1]; /* logarithmic axis */
- }
- }
- else {
- [xLinLog setState:0]; /* linear */
- }
- /* Now test y axis */
- if (datamax.y > 0.0 && datamin.y > 0.0 && datamax.y != datamin.y) {
- scale = fabs( (double)datamax.y - (double)datamin.y );
- linsum = 0.0;
- for (j=0; j<ncurves; j++) {
- for (i=1; i<npoints; i++) {
- tmp = ( (double)*(*(y+j)+i) - (double)*(*(y+j)+i-1) )
- / scale; /* avoid overflow */
- linsum += tmp*tmp;
- }
- }
- scale = log10((double)datamax.y/(double)datamin.y);
- /* what if datamax.y<datamin.y? */
- logsum = 0.0;
- for (j=0; j<ncurves; j++) {
- for (i=1; i<npoints;i++) {
- tmp = log10( (double)*(*(y+j)+i)/(double)*(*(y+j)+i-1) ) / scale;
- logsum += tmp*tmp;
- }
- }
- if (linsum < logsum) {
- [yLinLog setState:0]; /* linear axis */
- }
- else {
- [yLinLog setState:1]; /* logarithmic axis */
- }
- }
- else {
- [yLinLog setState:0]; /* linear */
- }
- [xLinLog display];
- [yLinLog display];
- return self;
- }
-
- - adjustPanels:(int)oldn :(int)newn
- {
- /*
- * Resize the linestyle matrix, the symbolstyle matrix, and
- * the legend form.
- * Also arrange to select and highlight only the top button in
- * each column of the linestyle and symbolstyle matrices.
- * This code could stand to be cleaned up.
- */
- char formtitle[80];
- int j, k;
-
- if (oldn >= newn) { /* have to delete some columns and revise the remaining */
- for (j=oldn-1; j>=newn; j--) {
- [lineText removeColAt:j andFree:YES]; /* Titles on Columns */
- [symbolText removeColAt:j andFree:YES]; /* Titles on Columns */
- [lineMatrix removeColAt:j andFree:YES];
- [symbolMatrix removeColAt:j andFree:YES];
- [legendForm removeEntryAt:j];
- }
- for (j=0; j<newn; j++) {
- if ( [ [lineMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */
- [ [lineMatrix cellAt:0 :j] setState:1];
- if ( [ [symbolMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */
- [ [symbolMatrix cellAt:0 :j] setState:1];
- for (k=1; k<N_LINE_STYLES; k++) {
- [ [lineMatrix cellAt:k :j] setState:0];
- }
- for (k=1; k<N_SYMBOL_STYLES; k++) {
- [ [symbolMatrix cellAt:k :j] setState:0];
- }
- sprintf(formtitle, "Curve %d", j+1);
- [legendForm setStringValue:formtitle at:j];
- [legendForm drawCellAt:j];
- sprintf(formtitle, "%d", j+1);
- [[lineText cellAt:0 :j] setStringValue:formtitle];
- [[symbolText cellAt:0 :j] setStringValue:formtitle];
- }
- [legendTitle setStringValue:"Legend" at:0];
- [lineText sizeToCells]; /* Titles on Columns */
- [symbolText sizeToCells]; /* Titles on Columns */
- [lineMatrix sizeToCells];
- [symbolMatrix sizeToCells];
- [legendForm sizeToFit];
- [ [lineText window] display]; /* Titles on Columns*/
- [ [symbolText window] display]; /* Titles on Columns*/
- [ [lineMatrix window] display]; /* redraw the whole window so extra */
- [ [symbolMatrix window] display]; /* columns get erased */
- [ [legendForm window] display];
- }
- if ( (oldn == 0) && (newn > 1) ) { /* can only happen first time */
- for (j=1; j<newn; j++) {
- [lineText addCol];
- [symbolText addCol];
- [lineMatrix addCol];
- if ( [ [lineMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */
- [ [lineMatrix cellAt:0 :j] setState:1];
- /* highlight 1st row new column -- this occurs automatically */
- [symbolMatrix addCol];
- if ( [ [symbolMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */
- [ [symbolMatrix cellAt:0 :j] setState:1];
- /* highlighting of 1st row new column occurs automatically */
- sprintf(formtitle, "Curve %d:", j+1);
- [legendForm addEntry:formtitle];
- sprintf(formtitle, "Curve %d", j+1);
- [legendForm setStringValue:formtitle at:j];
- [legendForm drawCellAt:j];
- sprintf(formtitle, "%d", j+1);
- [[lineText cellAt:0 :j] setStringValue:formtitle];
- [[symbolText cellAt:0 :j] setStringValue:formtitle];
- }
- [lineText sizeToCells]; /* Titles on Columns */
- [symbolText sizeToCells]; /* Titles on Columns */
- [lineMatrix sizeToCells];
- [symbolMatrix sizeToCells];
- [legendForm sizeToFit];
- [lineText display];
- [symbolText display];
- [lineMatrix display]; /* don't need to redraw the window here */
- [symbolMatrix display];
- [legendForm display];
- }
- if ( (oldn != 0) && (oldn < newn) ) { /* must add columns */
- for (j=0; j<oldn; j++) {
- if ( [ [lineMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */
- [ [lineMatrix cellAt:0 :j] setState:1];
- if ( [ [symbolMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */
- [ [symbolMatrix cellAt:0 :j] setState:1];
- for (k=1; k<N_LINE_STYLES; k++) {
- [ [lineMatrix cellAt:k :j] setState:0];
- }
- for (k=1; k<N_SYMBOL_STYLES; k++) {
- [ [symbolMatrix cellAt:k :j] setState:0];
- }
- sprintf(formtitle, "Curve %d", j+1);
- [legendForm setStringValue:formtitle at:j];
- [legendForm drawCellAt:j];
- sprintf(formtitle, "%d", j+1);
- [[lineText cellAt:0 :j] setStringValue:formtitle];
- [[symbolText cellAt:0 :j] setStringValue:formtitle];
- }
- for (j=oldn; j<newn; j++) {
- [lineText addCol];
- [symbolText addCol];
- [lineMatrix addCol];
- [ [lineMatrix cellAt:0 :j] setState:1];
- /* highlighting of 1st row new column occurs automatically */
- [symbolMatrix addCol];
- [ [symbolMatrix cellAt:0 :j] setState:1];
- /* highlighting of 1st row new column occurs automatically */
- sprintf(formtitle, "Curve %d:", j+1);
- [legendForm addEntry:formtitle];
- sprintf(formtitle, "Curve %d", j+1);
- [legendForm setStringValue:formtitle at:j];
- [legendForm drawCellAt:j];
- sprintf(formtitle, "%d", j+1);
- [[lineText cellAt:0 :j] setStringValue:formtitle];
- [[symbolText cellAt:0 :j] setStringValue:formtitle];
- }
- [legendTitle setStringValue:"Legend" at:0];
- [lineText sizeToCells]; /* Titles on Columns */
- [symbolText sizeToCells]; /* Titles on Columns */
- [lineMatrix sizeToCells];
- [symbolMatrix sizeToCells];
- [legendForm sizeToFit];
- [lineText display]; /* Titles on Columns */
- [symbolText display]; /* Titles on Columns */
- [lineMatrix display]; /* don't need to redraw the window here */
- [symbolMatrix display];
- [legendForm display];
- }
- [lineThickness setState:1 at:0:0]; /* reset line thickness to thin */
- [symbolSize setState:1 at :0:2]; /* reset symbol size to medium */
- [symbolSize display];
- [lineThickness display];
- return self;
- }
-
- // Go through the data set and find values for datamin.x,
- // datamax.x, datamin.y, datamax.y
- - findMinAndMax
- {
- if (x) {
- int i, j;
- datamin.x = datamax.x = x[0];
- for (i = 1; i < npoints; i++) {
- if (x[i] < datamin.x)
- datamin.x = x[i];
- else if (x[i] > datamax.x)
- datamax.x = x[i];
- }
- datamin.y = datamax.y = *(*(y+0)+0);
- for (j = 0; j < ncurves; j++) {
- for (i = 0; i < npoints; i++) {
- if (*(*(y+j)+i) < datamin.y)
- datamin.y = *(*(y+j)+i);
- else if (*(*(y+j)+i) > datamax.y)
- datamax.y = *(*(y+j)+i);
- }
- }
- }
- // reset min and max here (may want to change the placement of this)
- [self resetXmin:datamin.x];
- [self resetXmax:datamax.x];
- [self resetXinc:(datamax.x - datamin.x)/5.0];
- [self resetYmin:datamin.y];
- [self resetYmax:datamax.y];
- [self resetYinc:(datamax.y - datamin.y)/5.0];
-
- return self;
- }
-
-
- // Use the OpenPanel object to get a filename
- - open:sender
- {
- char const *fileTypes[2] = {0,0}; // this type is all ASCII files (?)
- // char const *fileTypes[2] = {"xyp",0};
- // this would be only files with an xyp extension
- char fname[1024];
-
- id openPanel = [OpenPanel new];
- if ([openPanel runModalForTypes:fileTypes]) {
- strncpy(fname, [openPanel filename], 1024);
- [self openFile:fname];
- }
- return self;
- }
-
- - openFile:(char *)dataFile
- {
- FILE *dataStream;
-
- if ((dataStream = fopen(dataFile, "r")) == NULL) {
- NXRunAlertPanel("Open", "Cannot open %s", "OK", NULL, NULL, dataFile);
- return self;
- }
-
- if ([self readData:dataStream] == 0) {
- NXRunAlertPanel("Read", "Couldn't read any data from %s", "OK",
- NULL, NULL, dataFile);
- fclose(dataStream);
- return self;
- }
- fclose(dataStream);
-
- [canvas initializeLegendBox];
-
- [self findMinAndMax];
-
- /* Check for linear or log on x and y axes */
- [self checkLinLog];
-
- [self drawPlot:self];
-
- return self;
- }
-
- @end
-